package com.zwh.rabbitmq.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.zwh.rabbitmq.config.aspect.MessageProcess;
import com.zwh.rabbitmq.config.constants.RabbitTemplateConstants;


/**
 * @author zwh
 * @date 2021/12/2 11:01
 **/
@Configuration
public class StrategyConfig {
    Logger logger = LoggerFactory.getLogger(StrategyConfig.class);

    /**
     * 自定义消息推送切面处理类
     *
     * param rabbitmqMessageRecordService 自定义注入的service类，保存消息推送记录
     *                                     Object rabbitmqMessageRecordService
     * @return
     */
    @Bean
    public MessageProcess messageProcess() {
        return new MessageProcess.Builder()
                //消息第一次发送前
                .preSend(messageInfo -> {
                    if (messageInfo == null) {
                        return;
                    }
                    //保存消息
                    // 默认设置为发送失败
                    messageInfo.setMessageStatus(BooleanEnum.NO.getId());
                    /**

                     note: 这里保存消息记录表数据时，要注意事务的传递性问题
                     避免多线程调用推送方法时， 事务未及时提交， rabbitmq异步结果回调线程不能查询到 记录表的数据。
                     @Transactional(readOnly = false, rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
                     public void save(RabbitmqMessageRecordDto messageRecordDto) {
                        // 保存操作
                     }
                     */
                    // rabbitmqMessageRecordService.save(messageInfo);
                })

                //消息投递成功(包含路由失败的)
                .messageAck(messageInfo -> {
                    // 消息状态为true
                    if (messageInfo == null) {
                        return;
                    }
//                    Object messageStatus = RedisUtil.get(messageInfo.getSendMessageId());
//                    if (messageStatus == null) {
//                        rabbitmqMessageRecordService.updateMessageSuccessfulBySendMessageId(messageInfo.getSendMessageId());
//                    } else {
//                        RedisUtil.del(messageInfo.getSendMessageId());
//                    }
                })

                //消息投递失败
                .messageNack(messageInfo -> {
                    if (messageInfo == null) {
                        return;
                    }
                    //更新消息状态为失败，添加失败原因
//                    rabbitmqMessageRecordService.updateMessageFailureBySendMessageId(messageInfo.getSendMessageId(),
//                            messageInfo.getDescription());
                })

                //提供需要重发的消息
//                .pickResendMessages(() -> {
//                    //查找需要重发的消息,满足
//                    // 1.重发次数小于3
//                    // 2.上一次发送时间为3秒钟之前的(confirmCallback是异步的)
//                    // 3.按上一次发送时间顺序排序(先发等待久的)
//                    return messageService.selectNeedResendMessage();
//                })
//
//                //消息重发前
//                .preResend(id -> {
//                    //消息重发数+1,修改上一次发送时间为当前时间
//                    messageService.updateResendTimesAndLastSendTime(id);
//                })

                //消息路由失败
                .messageRouteFail((message, messageProperties, messageBody, exchange, routingKey, errMsg) -> {
                    //保存路由失败的消息
                    logger.error("消息路由失败,exchange:{}, routingKey:{}, msg:{}", exchange, routingKey, errMsg);
                    String messageId = (String) message.getMessageProperties().getHeaders()
                            .get(RabbitTemplateConstants.MESSAGE_HEADER_ID);
                    if (messageId == null) {
                        return;
                    }
                    // 使用redis保存消息id装填，用于 messageAck 回调中处理方法
//                    RedisUtil.set(messageId, "1", 300);
//                    rabbitmqMessageRecordService.updateMessageFailureBySendMessageId(messageId, errMsg);
//                    messageService.saveUnRoutableMessage(messageProperties, messageBody, exchange, routingKey);
                })
                .build();
    }
}
